//------------------------------------------------------------------------------
// StackString.h
//------------------------------------------------------------------------------
// File provided for Microsoft Shared Source.
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF 
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO 
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A 
// PARTICULAR PURPOSE.
//------------------------------------------------------------------------------
//
// Stack based string class
//
//------------------------------------------------------------------------------

#pragma once

//------------------------------------------------------------------------------
// CStackString
//------------------------------------------------------------------------------
//
// Sized stack string
//
//------------------------------------------------------------------------------

template<DWORD cch> class CStackString
{
public:
    CStackString();

    // Operations
    BOOL operator<(const WCHAR *pwszSrc) const;
    BOOL operator>(const WCHAR *pwszSrc) const;
    BOOL operator!=(const WCHAR *pwszSrc) const;
    BOOL operator==(const WCHAR *pwszSrc) const;
    BOOL IsEmpty() const;
    DWORD Length() const;
    DWORD Size() const;
    HRESULT Copy(const WCHAR *pwszSrc);
    HRESULT Copy(const WCHAR *pwszSrc, DWORD cchSrc);
    HRESULT CoTaskMemCopy(__deref_out PWSTR *ppsz);
    void Empty();
    HRESULT Load(UINT uiResId);
    HRESULT Load(__in HINSTANCE hinst, UINT uiResId);
    HRESULT Append(const WCHAR ch);
    HRESULT Append(const WCHAR *pwsz);
    HRESULT Append(const WCHAR *pwsz, DWORD cchMaxAppend);
    HRESULT Append(UINT uiResId);
    HRESULT Append(__in HINSTANCE hinst, UINT uiResId);
    int Compare(const WCHAR *pwsz);
    int CompareNoCase(const WCHAR *pwsz);  // uses the current thread locale
    HRESULT Format(const WCHAR *pwszFormat, ...);
    HRESULT VFormat(const WCHAR *pwszFormat, __in va_list argList);
    void ToLower();
    void ToUpper();

    operator WCHAR *();
    operator const WCHAR *() const;
    operator BYTE *();

private:
    WCHAR _wsz[cch];
};

template<DWORD cch> inline CStackString<cch>::CStackString()
{
    _wsz[0] = 0;
}

template<DWORD cch> inline BOOL CStackString<cch>::operator<(const WCHAR *pwszSrc) const
{
    return lstrcmp(_wsz, pwszSrc) < 0;
}

template<DWORD cch> inline BOOL CStackString<cch>::operator>(const WCHAR *pwszSrc) const
{
    return lstrcmp(_wsz, pwszSrc) > 0;
}

template<DWORD cch> inline BOOL CStackString<cch>::operator!=(const WCHAR *pwszSrc) const
{
    return !operator==(pwszSrc);
}

template<DWORD cch> inline BOOL CStackString<cch>::operator==(const WCHAR *pwszSrc) const
{
    return lstrcmp(_wsz, pwszSrc) == 0;
}

template<DWORD cch> inline CStackString<cch>::operator WCHAR *()
{
    return _wsz;
}

template<DWORD cch> inline CStackString<cch>::operator const WCHAR *() const
{
    return _wsz;
}

template<DWORD cch> inline CStackString<cch>::operator BYTE *()
{
    return (BYTE *)_wsz;
}

template<DWORD cch> inline BOOL CStackString<cch>::IsEmpty() const
{
    return _wsz[0] == 0;
}

template<DWORD cch> inline DWORD CStackString<cch>::Length() const
{
    size_t cchStr;
    return (S_OK == StringCchLength(_wsz, cch, &cchStr)) ? (DWORD)cchStr : 0;
}

template<DWORD cch> inline DWORD CStackString<cch>::Size() const
{
    return cch;
}

template<DWORD cch> inline HRESULT CStackString<cch>::Copy(const WCHAR *pwszSrc)
{
    return StringCchCopy(_wsz, cch, pwszSrc);
}

template<DWORD cch> inline HRESULT CStackString<cch>::Copy(const WCHAR *pwszSrc, DWORD cchCopy)
{
    return StringCchCopyN(_wsz, cch, pwszSrc, cchCopy);
}

template<DWORD cch> inline HRESULT CStackString<cch>::CoTaskMemCopy(__deref_out PWSTR *ppsz)
{
    return SHStrDup(_wsz, ppsz);
}

template<DWORD cch> inline void CStackString<cch>::Empty()
{
    _wsz[0] = 0;
}

template<DWORD cch> inline HRESULT CStackString<cch>::Load(UINT uiResId)
{
    return Load(_AtlBaseModule.GetModuleInstance(), uiResId);
}

template<DWORD cch> inline HRESULT CStackString<cch>::Load(__in HINSTANCE hinst, UINT uiResId)
{
    return LoadString(hinst, uiResId, _wsz, cch) ? S_OK : HRESULT_FROM_WIN32(GetLastError());
}

template<DWORD cch> inline HRESULT CStackString<cch>::Append(const WCHAR *pwsz)
{
    return StringCchCat(_wsz, cch, pwsz);
}

template<DWORD cch> inline HRESULT CStackString<cch>::Append(const WCHAR *pwsz, DWORD cchMaxAppend)
{
    return StringCchCatN(_wsz, cch, pwsz, cchMaxAppend);
}

template<DWORD cch> inline HRESULT CStackString<cch>::Append(UINT uiResId)
{
    return Append(WfxGetInstanceHandle(), uiResId);
}

template<DWORD cch> inline HRESULT CStackString<cch>::Append(__in HINSTANCE hinst, UINT uiResId)
{
    CStackString<cch> str;
    HRESULT hr = str.Load(hinst, uiResId);
    if (SUCCEEDED(hr))
    {
        hr = Append(str);
    }
    return hr;
}

template<DWORD cch> inline HRESULT CStackString<cch>::Append(const WCHAR ch)
{
    return Append(&ch, 1);
}

template<DWORD cch> inline int CStackString<cch>::Compare(const WCHAR *pwsz)
{
    return lstrcmp(_wsz, pwsz);
}

template<DWORD cch> inline int CStackString<cch>::CompareNoCase(const WCHAR *pwsz)
{
    return lstrcmpi(_wsz, pwsz);
}

template<DWORD cch> HRESULT CStackString<cch>::Format(const WCHAR *pwszFormat, ...)
{
    HRESULT hr;
    va_list argList;
    va_start(argList, pwszFormat);
    hr = VFormat(pwszFormat, argList);
    va_end(argList);
    return hr;
}

template<DWORD cch> HRESULT CStackString<cch>::VFormat(const WCHAR *pwszFormat, __in va_list argList)
{
    return StringCchVPrintf(_wsz, cch, pwszFormat, argList);
}

template<DWORD cch> inline void CStackString<cch>::ToLower()
{
    CharLower(_wsz);
}

template<DWORD cch> inline void CStackString<cch>::ToUpper()
{
    CharUpper(_wsz);
}

// Define a few common string sizes

typedef CStackString<256> CBufString;
typedef CStackString<MAX_PATH> CPathString;
